package handler

import (
	"context"
	"errors"
	"github.com/golang/protobuf/ptypes/empty"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"pm_back_server/project-server/global"
	"pm_back_server/project-server/model"
	"pm_back_server/project-server/proto"
)

func HandleProjectModelToResponse(projectModel *model.Project) *proto.ProjectResponseInfo {
	return &proto.ProjectResponseInfo{
		Id:      uint64(projectModel.ID),
		Name:    projectModel.Name,
		Desc:    projectModel.Desc,
		Cover:   projectModel.Cover,
		GroupId: projectModel.GroupId,
	}
}

// CreateProject /* 创建项目
func (p *ProjectServer) CreateProject(ctx context.Context, req *proto.CreateProjectInfo) (*proto.ProjectResponseInfo, error) {
	var group model.Group
	result := global.DB.First(&group, req.GroupId)
	if result.RowsAffected == 0 {
		zap.S().Errorw("[CreateProject] 查询 [团队] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}

	if group.LeaderId != req.LeaderId {
		zap.S().Errorw("[CreateProject] 校验 [权限] 失败")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}

	project := model.Project{
		Name:    req.Name,
		Desc:    req.Desc,
		Cover:   req.Cover,
		GroupId: req.GroupId,
	}
	result = global.DB.Create(&project)

	if result.Error != nil {
		zap.S().Errorw("[CreateProject] 创建 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return HandleProjectModelToResponse(&project), nil
}

// GetProjectById /* 通过项目ID查询项目
func (p *ProjectServer) GetProjectById(ctx context.Context, req *proto.ProjectIdInfo) (*proto.ProjectResponseInfo, error) {
	var project model.Project
	result := global.DB.First(&project, req.Id)
	if result.Error != nil {
		zap.S().Errorw("[GetProjectById] 查询 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	if result.RowsAffected == 0 {
		zap.S().Errorw("[GetProjectById] 查询 [项目] 失败")
		return nil, status.Errorf(codes.NotFound, ProjectNotFound)
	}
	return HandleProjectModelToResponse(&project), nil
}

// GetProjectListByGroupId /* 通过团队ID查询项目列表
func (p *ProjectServer) GetProjectListByGroupId(ctx context.Context, req *proto.GroupIdInfo) (*proto.ProjectListResponseInfo, error) {
	var group model.Group
	result := global.DB.First(&group, req.Id)
	if result.RowsAffected == 0 {
		zap.S().Errorw("[GetProjectListByGroupId] 查询 [团队] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}

	var projects []model.Project
	result = global.DB.Model(&model.Project{}).Where("group_id = ?", req.Id).Find(&projects)
	if result.Error != nil {
		zap.S().Errorw("[GetProjectListByGroupId] 查询 [项目列表] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	rsp := &proto.ProjectListResponseInfo{}
	for _, project := range projects {
		rsp.ProjectList = append(rsp.ProjectList, HandleProjectModelToResponse(&project))
	}
	return rsp, nil
}

// UpdateProject /* 更新项目信息
func (p *ProjectServer) UpdateProject(ctx context.Context, req *proto.UpdateProjectInfo) (*empty.Empty, error) {
	var project model.Project
	result := global.DB.First(&project, req.Id)
	if result.Error != nil {
		zap.S().Errorw("[UpdateProject] 查询 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	if result.RowsAffected == 0 {
		zap.S().Errorw("[UpdateProject] 查询 [项目] 失败")
		return nil, status.Errorf(codes.NotFound, ProjectNotFound)
	}
	if !CheckAuthority(req.GroupId, req.UserId) {
		zap.S().Errorw("[UpdateProject] 校验 [权限] 失败")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}

	project.Name = req.Name
	project.Desc = req.Desc
	project.Cover = req.Cover
	result = global.DB.Save(&project)
	if result.Error != nil {
		zap.S().Errorw("[UpdateProject] 更新 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &empty.Empty{}, nil
}

// DeleteProject /* 删除项目
func (p *ProjectServer) DeleteProject(ctx context.Context, req *proto.DeleteProjectInfo) (*empty.Empty, error) {
	// 校验是否具有权限
	if !CheckAuthority(req.GroupId, req.UserId) {
		zap.S().Errorw("[DeleteProject] 校验 [权限] 失败")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}
	// 校验项目是否存在
	var project model.Project
	result := global.DB.First(&project, req.Id)
	if result.Error != nil {
		zap.S().Errorw("[DeleteProject] 查询 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	if result.RowsAffected == 0 {
		zap.S().Errorw("[DeleteProject] 查询 [项目] 失败")
		return nil, status.Errorf(codes.NotFound, ProjectNotFound)
	}
	// 删除项目所属的迭代
	if err := p.DeleteIterationByProjectId(&proto.ProjectIdInfo{Id: req.Id}); err != nil {
		zap.S().Errorw("[DeleteProject] 删除 [迭代] 失败")
		return nil, status.Errorf(codes.Internal, err.Error())
	}
	// 删除项目所属的任务
	if err := p.DeleteTaskByProjectId(&proto.ProjectIdInfo{Id: req.Id}); err != nil {
		zap.S().Errorw("[DeleteProject] 删除 [任务] 失败")
		return nil, status.Errorf(codes.Internal, err.Error())
	}
	// 删除项目
	result = global.DB.Model(&model.Project{}).Delete(&project, req.Id)
	if result.Error != nil {
		zap.S().Errorw("[DeleteProject] 删除 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return &empty.Empty{}, nil
}

// DeleteProjectByGroupId /* 通过团队ID删除项目
func (p *ProjectServer) DeleteProjectByGroupId(req *proto.GroupIdInfo) error {
	if !CheckGroupExist(req.Id) {
		zap.S().Errorw("[DeleteProjectById] 查询 [团队] 失败")
		return errors.New("删除项目失败")
	}

	var projects []model.Project
	result := global.DB.Model(&model.Project{}).Where("group_id = ?", req.Id).Delete(&projects)
	if result.Error != nil {
		zap.S().Errorw("[DeleteProjectById] 删除 [项目] 失败")
		return errors.New("删除项目失败")
	}

	return nil
}

// GetGroupIdByProjectId /* 通过项目ID查询团队ID
func (p *ProjectServer) GetGroupIdByProjectId(projectId uint64) uint64 {
	var project model.Project
	result := global.DB.First(&project, projectId)
	if result.RowsAffected == 0 {
		return 0
	}
	return project.GroupId
}

// CheckProjectExist /* 检验项目是否存在
func CheckProjectExist(projectId uint64) bool {
	var project model.Project
	result := global.DB.First(&project, projectId)
	if result.RowsAffected == 0 {
		return false
	}
	return true
}
